/*--------------------------------------------------------------------------
		此项目为山东建筑大学 物联网工程专业 RFID课程设计题目
		基于51单片机模拟ID64协议校验
			本设计选用的卡片类型为ID64格式的工作于TTF方式的只读卡。
		卡片出厂时已将64位的卡号信息固化在卡片的非易失性存储器内。
		卡片进入读卡器125KHz的射频场后得电复位，立即主动将64位卡号信息持续循环向读卡器发送，
		读卡器从接收的64位卡号信息中经解码、校验得到40位卡片序列号，然后通过输出口发送给上位机。
--------------------------------------------------------------------------*/

/*--------------------项目编写者为	物联22级李宇杰 --------------------*/

/*--------------------------------------------------------------------------
		注意事项：
			1.由于没有射频芯片HTRC110，所以使用上位机通过串口模拟数据，此项目主要是为了校验id64协议，
			2.串口设计波特率为4800
			3.ID64编码器（上位机）有自己的串口通信协议，详见PPT：125KHz低频读卡器设计
			4.ID64编码器（上位机）可以一键完成随机产生ID64编码
--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------
		接线说明：
			1.使用P2口连接8pin排线至8个led
			2.P1^5连接至蜂鸣器模块
--------------------------------------------------------------------------*/
#include <REGX52.H>
#include <string.h>
#include <INTRINS.H>

#define Rx_size 11

sbit Buzzer=P1^5;

unsigned char UART_ReceiveBuffer[Rx_size];
unsigned char Rx_count = 0;
unsigned char DataReady = 0;  // 新增数据就绪标志
unsigned char data_right = 0;

void UART_Init()
{
    SCON = 0x50;
    PCON |= 0x80;
    TMOD &= 0x0F;        // 设置定时器模式
    TMOD |= 0x20;        // 设置定时器模式
    TL1 = 0xF3;          // 设定定时初值
    TH1 = 0xF3;          // 设定定时器重装值
    ET1 = 0;             // 禁止定时器1中断
    TR1 = 1;             // 启动定时器1
    EA = 1;
    ES = 1;
}

void UART_SendByte(unsigned char Byte)
{
    SBUF = Byte;
    while (TI == 0);
    TI = 0;
}

/**
  * @brief  蜂鸣器私有延时函数，延时500us
  */
void Buzzer_Delay500us()		//@12.000MHz
{
	unsigned char i;

	_nop_();
	i = 247;
	while (--i);
}

/**
  * @brief  蜂鸣器发声
  * @param  ms 发声的时长，范围：0~32767
  */
void Buzzer_Time(unsigned int ms)
{
	unsigned int i;
	for(i=0;i<ms*2;i++)
	{
		Buzzer=!Buzzer;
		Buzzer_Delay500us();
	}
}

void DelayXms(unsigned char ms)	//@12.000MHz
{
	while(ms--){
		unsigned char data i, j;

		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}

/**
  * @brief  数据处理函数（ID64数据提取与转换）
  * @param  pBuffer 接收缓冲区指针
  */
void Data_Process(unsigned char *pBuffer)
{
	unsigned char i,j;
	unsigned char id64[8];
	unsigned char *p = id64;
    unsigned char buffer[5]; // 存储10个5位组转换的字节
	unsigned char bitBuffer[7]; // 存储56位数据（7字节）
	unsigned char out_buffer[11];//dai ling de buffer
	int bitIndex = 0;
	
    // 1. 检查起始符、结束符和数据长度
    if (pBuffer[0] != 0xFE || pBuffer[10] != 0xFE || pBuffer[1] != 0x08) {
        return; // 校验失败，直接返回
    }

    // 2. 提取ID64数据（8字节）
    for (i = 0; i < 8; i++) {
        id64[i] = pBuffer[2 + i];
    }

    // 3. 验证前9位全1且最后1位为0
    // 3.1 检查第一个字节是否为0xFF
    if (id64[0] != 0xFF) {
	    for(i = 0; i < Rx_size; i++)
		{
			UART_SendByte(pBuffer[i]);  // 原样返回数据
		}
		data_right = 0;
		return;
	}
    
    // 3.2 检查第二个字节的最高位是否为1
    if ((id64[1] & 0x80) == 0) {
	    for(i = 0; i < Rx_size; i++)
		{
			UART_SendByte(pBuffer[i]);  // 原样返回数据
		}
		data_right = 0;
		return;
	}
    
    // 3.3 检查最后一个字节的最低位是否为0
    if ((id64[7] & 0x01) != 0) {
	    for(i = 0; i < Rx_size; i++)
		{
			UART_SendByte(pBuffer[i]);  // 原样返回数据
		}
		data_right = 0;
		return;
	}
	// 3.4 检查行校验位
	out_buffer[0]=(id64[1]&0X7C)>>2;
	out_buffer[1]=((id64[1]&0X03)<<3)|((id64[2]&0XE0)>>5);
	out_buffer[2]=(id64[2]&0X1F);
	out_buffer[3]=(id64[3]&0XF8)>>3;
	out_buffer[4]=((id64[3]&0X07)<<2)|((id64[4]&0XC0)>>6);
	out_buffer[5]=((id64[4]&0X3E)>>1);
	out_buffer[6]=((id64[4]&0X01)<<4)|((id64[5]&0XF0)>>4);
	out_buffer[7]=((id64[5]&0X0F)<<1)|((id64[6]&0X80)>>7);
	out_buffer[8]=((id64[6]&0X7C)>>2);
	out_buffer[9]=((id64[6]&0X03)<<3)|((id64[7]&0XE0)>>5);
	out_buffer[10]=(id64[7]&0X1E);
	for(j=0;j<10;j++)
	{
		int count=0;
		for(i=4;i>0;i--)
		{
			if(((out_buffer[j]>>i)&0X01)==1)
			{
				count++;
			}	
		}
		if((count%2)!=(out_buffer[j]&0x01))
		{
			for(i = 0; i < Rx_size; i++)
			{
				UART_SendByte(pBuffer[i]);  // 原样返回数据
			}
			data_right = 0;
			return;
		}
	}
	// 3.4 检查lie校验位
	for(j=4;j>0;j--)
	{
		int count =0;
		for(i=0;i<10;i++){
			count ^=((out_buffer[i]>>j)&0x01);
		}
		if(count!=((out_buffer[10]>>j)&0x01))
		{
			for(i = 0; i < Rx_size; i++)
			{
				UART_SendByte(pBuffer[i]);  // 原样返回数据
			}
			data_right = 0;
			return;
		}
	}
	
	
//    if ((id64[1] & ) != 0) {
//	    for(i = 0; i < Rx_size; i++)
//		{
//			UART_SendByte(pBuffer[i]);  // 原样返回数据
//		}
//		data_right = 0;
//		return;
//	  }
    // 4. 从第9位开始提取40位数据（10组x4位）
    // 4.1 手动提取56位数据（跳过前8位和后5位）
    // 跳过第一个字节的前8位（已验证为全1）
    // 从第二个字节开始提取（跳过最高位）
    for (i = 1; i < 8; i++) { // 处理id64[1]到id64[7]
        bitBuffer[bitIndex++] = id64[i];//bitBuffer[0-6]
    }

    // 4.2 从56位中提取10组5位数据
	buffer[0]=((bitBuffer[0]&0x78)<<1)|(((bitBuffer[0]&0x03)<<2)|((bitBuffer[1]&0xC0)>>6));
	buffer[1]=((bitBuffer[1]&0x1E)<<3)|((bitBuffer[2]&0xF0)>>4);
	buffer[2]=(((bitBuffer[2]&0x07)<<5)|((bitBuffer[3]&0x80)>>3))|((bitBuffer[3]&0x3C)>>2);
	buffer[3]=(((bitBuffer[3]&0x01)<<7)|((bitBuffer[4]&0xE0)>>1))|(bitBuffer[4]&0x0F);
	buffer[4]=((bitBuffer[5]&0x78)<<1)|(((bitBuffer[5]&0x03)<<2)|((bitBuffer[6]&0xC0)>>6));
		
    // 5. 通过串口输出结果（10个字符）
    for (i = 0; i < 5; i++) {
        UART_SendByte(buffer[i]);
    }
	data_right = 1;
}

//    for(i = 0; i < Rx_size; i++)
//    {
//        UART_SendByte(pBuffer[i]);  // 原样返回数据
//    }


void main()
{
    UART_Init();        // 串口初始化
    while (1)
    {
        if(DataReady)  // 检测数据就绪标志
        {
            Data_Process(UART_ReceiveBuffer);  // 调用数据处理函数
			if(data_right){
				P2 = 0xDA;//11011010
				Buzzer_Time(200);
				P2 = 0xFF;
			}
			else{
				P2 = 0x6D;//01101101
				Buzzer_Time(200);
				P2 = 0xFF;
				DelayXms(100);
				P2 = 0x6D;//01101101
				Buzzer_Time(200);
				P2 = 0xFF;
			}
            DataReady = 0;  // 重置就绪标志
            Rx_count = 0;   // 重置接收计数器
        }

    }
}

void UART_Routine() interrupt 4       //串口中断
{
    if (RI == 1)                    // 检测接收中断
    {
        if (Rx_count < Rx_size)
        {
            UART_ReceiveBuffer[Rx_count] = SBUF;  // 存储接收数据
            Rx_count++;  // 增加计数器
        }

        if (Rx_count == Rx_size)  // 接收完成
        {
            DataReady = 1;  // 设置就绪标志 
        }
		
        RI = 0;  // 清除接收标志,,,手动复位
    }
}
